package info.liuxing.rest;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.*;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * RestTemplate
 *
 * @author liuxing (SE)
 * @summary RestTemplate
 * @Copyright (c) 2017, Lianjia Group All Rights Reserved.
 * @since 2017-12-11 16:39
 */
public class RestClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(RestClient.class);

    private static final RestTemplate restTemplate;

    static {

        HttpClientBuilder builder = HttpClients.custom();
        builder.setConnectionTimeToLive(30, TimeUnit.SECONDS);
        builder.setMaxConnTotal(1000);
        builder.setMaxConnPerRoute(1000);

        builder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));

        // 保持长连接配置，需要在头添加Keep-Alive
        // 该策略依赖响应头的Keep-Alive参数：如 Keep-Alive: timeout=5, max=100 单位秒
        // 否则则依赖ConnectionTimeToLive的设置
        builder.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE);

        try {
            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
            builder.setSSLContext(sslContext);
        } catch (Exception e) {
            e.printStackTrace();
        }

        RequestConfig requestConfig = RequestConfig.custom()
                // 读写超时
                .setSocketTimeout(5000)
                // 连接超时
                .setConnectTimeout(5000)
                // 从连接池中获取连接的时间，非请求时间
                .setConnectionRequestTimeout(200)
                // 最大重定向次数
                .setMaxRedirects(10)
                // 开启gzip
                .setContentCompressionEnabled(true)
                .build();

        builder.setDefaultRequestConfig(requestConfig);

        // httpClient连接配置，底层是配置RequestConfig
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(builder.build());
        requestFactory.setBufferRequestBody(false);

        restTemplate = new RestTemplate(messageConverters());
        restTemplate.setRequestFactory(requestFactory);

        LOGGER.debug("RestClient初始化完成");
    }

    public static RestTemplate client() {
        return restTemplate;
    }

    /**
     * 内容转换器
     *
     * @return
     */
    private static List<HttpMessageConverter<?>> messageConverters() {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();

        // 文件转换器
        messageConverters.add(new ResourceHttpMessageConverter());
        // 字节转换器
        messageConverters.add(new ByteArrayHttpMessageConverter());
        // 文本转换器
        messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        // json转换器
        messageConverters.add(new MappingJackson2HttpMessageConverter());
        // xml转换器
        messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
        // 表单转换器
        messageConverters.add(new FormHttpMessageConverter());

        // 最低优先的转换器
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        jsonConverter.setSupportedMediaTypes(Arrays.asList(MediaType.ALL));

        messageConverters.add(jsonConverter);

        return messageConverters;
    }
}
